package com.example.mybatis.interceptor;

import com.example.common.utils.Statistics;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Properties;

/**
 * @author zty
 * @apiNote 拦截器， 可参考{@link com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor}
 * @user nav1c
 * @date 2023/9/1 11:51
 * @project advanced-cloud
 */
@Intercepts({
        @Signature(
                type = Executor.class,
                method = LogInterceptor.UPDATE,
                args = {MappedStatement.class, Object.class}
        ),
        @Signature(
                type = Executor.class, //org.apache.ibatis.executor.Executor 别搞错
                method = LogInterceptor.QUERY, //这是Executor的方法，点进去可以看到
                args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class} //这是query的参数，不能错。
        )
})
@Slf4j
@Component
public class LogInterceptor implements Interceptor {

    public static final String QUERY = "query";

    public static final String UPDATE = "update";

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        final Method method = invocation.getMethod();
        final Object[] args = invocation.getArgs();
        final String methodName = method.getName();
        String invocationInfo = "target is : " + invocation.getTarget()
                + "\n method is : " + method
                + "\n args is : " + Arrays.toString(args);
        Statistics.logInfo(log, "intercept", invocationInfo);
        if (!QUERY.equals(methodName) && !UPDATE.equals(methodName)){
           return invocation.proceed();
        }
        final MappedStatement mappedStatement = (MappedStatement) args[0];//第一个参数是sql?
        final Object parameter = args[1]; //第二个参数是预编译的占位符参数？
        if (QUERY.equals(methodName)){
            final RowBounds rowBounds = (RowBounds) args[2];
            log.info("rowRounds is : {}", rowBounds); //？
            final ResultHandler<?> resultHandler = (ResultHandler<?>) args[3]; //？
            log.info("resultHandler is : {}", resultHandler);
            if (args.length == 6){
                final CacheKey cacheKey = (CacheKey) args[4];
                log.info("cacheKey is : {}", cacheKey);
                final BoundSql boundSql = (BoundSql) args[5];
                log.info("boundSql is : {}", boundSql);
            }
        }
        final String sql = mappedStatement.getBoundSql(parameter).getSql();
        log.info("Executing SQL : {}", sql);
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        Statistics.logInfo(log, "plugin", target);
        return Interceptor.super.plugin(target);
    }

    @Override
    public void setProperties(Properties properties) {
        Statistics.logInfo(log, "setProperties", properties);
        Interceptor.super.setProperties(properties);
    }
}
